// CPPClassLibrary.h

#pragma once

using namespace System;

#pragma unmanaged

#include <stdio.h>
#include <string.h>

//static int Hues[16581375];
//static double Saturations[16581375];
//static double Luminances[16581375];
static bool Initialized = false;

static void Initialize(void)
{
	//memset(Hues, sizeof(Hues), 0);
	//memset(Saturations, sizeof(Saturations), 0);
	//memset(Luminances, sizeof(Luminances), 0);
}

static void CalcRGBToHSL(unsigned char red, unsigned char green, unsigned char blue, int *pHue, double *pSaturation, double *pLuminance)
{
	double r = ((double)red / 255.0);
	double g = ((double)green / 255.0);
	double b = ((double)blue / 255.0);

	double minRG;
	double maxRG;

	if (r > g)
	{
		minRG = g;
		maxRG = r;
	}
	else
	{
		minRG = r;
		maxRG = g;
	}            
    
	double min = minRG > b ? b : minRG;
	double max = maxRG > b ? maxRG : b;
	double delta = max - min;

	// get luminance value
	*pLuminance = (max + min) / 2;

	if (delta == 0)
	{
		// gray color
		*pHue = 0;
		*pSaturation = 0.0;
	}
	else
	{
		// get saturation value
		*pSaturation = (*pLuminance < 0.5) ? (delta / (max + min)) : (delta / (2 - max - min));

		// get hue value
		double del_r = (((max - r) / 6) + (delta / 2)) / delta;
		double del_g = (((max - g) / 6) + (delta / 2)) / delta;
		double del_b = (((max - b) / 6) + (delta / 2)) / delta;
		double hue;

		if (r == max)
			hue = del_b - del_g;
		else if (g == max)
			hue = (1.0 / 3) + del_r - del_b;
		else
			hue = (2.0 / 3) + del_g - del_r;

		// correct hue if needed
		if (hue < 0)
			hue += 1;
		if (hue > 1)
			hue -= 1;

		*pHue = (int)(hue * 360);
	}
}
	
//static void RGBToHSL(unsigned char red, unsigned char green, unsigned char blue, int *pHue, double *pSaturation, double *pLuminance)
//{			        
//	int key = ((int)red << 16) + ((int)green << 8) + (int)blue;
//	int hue = Hues[key];
//	double saturation = Saturations[key];
//	double luminance = Luminances[key];
//
//	// convert to HSL
//	if (hue == 0 && saturation == 0.0 && luminance == 0.0)
//	{
//		CalcRGBToHSL(red, green, blue, pHue, pSaturation, pLuminance);
//		Hues[key] = *pHue;
//		Saturations[key] = *pSaturation;
//		Luminances[key] = *pLuminance;
//	}	
//	else
//	{
//		*pHue = hue; 
//		*pSaturation = saturation;
//		*pLuminance = luminance;
//	}
//}		

static void RGBToHSL(unsigned char red, unsigned char green, unsigned char blue, int *pHue, double *pSaturation, double *pLuminance)
{			        
	int hue = 0;
	double saturation = 0.0;
	double luminance = 0.0;

	// convert to HSL
	CalcRGBToHSL(red, green, blue, pHue, pSaturation, pLuminance);		
}		


static inline double Hue_2_RGB(double v1, double v2, double vH)
{
	if (vH < 0)
		vH += 1;
	else if (vH > 1)
		vH -= 1;

	if ((6 * vH) < 1)
		return (v1 + (v2 - v1) * 6 * vH);
	if ((2 * vH) < 1)
		return v2;
	if ((3 * vH) < 2)
		return (v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6);

	return v1;
}

static void CalcRGBFromHSL(int hueIn, double luminance, double saturation, unsigned char *red, unsigned char *green, unsigned char *blue)
{	
	if (saturation == 0)
	{
		// gray values
		unsigned char b = (unsigned char)(luminance * 255);
		*red = b;
		*green = b;
		*blue = b;
	}
	else
	{
		double v1, v2;
		double hue = (double)hueIn / 360;

		v2 = (luminance < 0.5) ?
			(luminance * (1 + saturation)) :
			((luminance + saturation) - (luminance * saturation));
		v1 = 2 * luminance - v2;

		*red = (unsigned char)(255 * Hue_2_RGB(v1, v2, hue + (1.0 / 3)));
		*green = (unsigned char)(255 * Hue_2_RGB(v1, v2, hue));
		*blue = (unsigned char)(255 * Hue_2_RGB(v1, v2, hue - (1.0 / 3)));        
	}
}

void SobelEdge( unsigned char *src, unsigned char *dst, unsigned char *dst2, int dstOffset, int srcOffset, int dstStride, int srcStride, int startX, int startY, int stopX, int stopY, bool scaleIntensity);

void FilterHSLLinear(int pixelSize, unsigned char *ptr, int startX, int startY, int stopX, int stopY, int offset,
				   double inLuminanceMin, double inLuminanceMax, double outLuminanceMin, double outLuminanceMax,
				   double inSaturationMin, double inSaturationMax, double outSaturationMin, double outSaturationMax);

void DoFilterImageRGB(int pixelSize, int *pkernel, unsigned char *src, unsigned char *dst, 
				   int startX, int startY, int stopX, int stopY, int size, int srcStride, int divisor, bool dynamicDivisorForEdges,
				   int threshold, int srcOffset, int dstOffset);

void DoFilterImageGrayscale(int pixelSize, int *pkernel, unsigned char *src, unsigned char *dst, 
				   int startX, int startY, int stopX, int stopY, int size, int srcStride, int divisor, bool dynamicDivisorForEdges,
				   int threshold, int srcOffset, int dstOffset);

void ResizeBicubic(unsigned char *src, unsigned char *dst, double xFactor, double yFactor, int height, int width, int newHeight, int newWidth, int srcStride, int dstOffset);

void ResizeBilinear(unsigned char *src, unsigned char *dst, double xFactor, double yFactor, int height, int width, int newHeight, int newWidth, int srcStride, int dstOffset, int pixelSize);

void ResizeNearestNeighbor3(unsigned char *baseSrc, unsigned char *baseDst, double xFactor, double yFactor, int height, int width, int newHeight, int newWidth, int pixelSize, int srcStride, int dstStride);


